package cn.edu.zut.sunday.base.controller;

import cn.edu.zut.sunday.base.domain.BaseEntity;
import cn.edu.zut.sunday.base.service.GenericService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

@Slf4j
@CrossOrigin
public abstract class GenericController
  <T extends BaseEntity<I>, I extends Serializable, M extends GenericService<T, I>>
  extends BaseControllerHandler<T, I> {

    protected M service;

    /**
     * @param id entity id
     */
    @ApiOperation(value = "根据ID信息删除一个数据库中的实体")
    @DeleteMapping(value = "/delete/{id}", produces = "application/json")
    @ResponseBody
    public void delete(@PathVariable I id) {
        this.service.delete(id);
    }

    /**
     * @param id entity id
     * @return found entity
     */
    @ApiOperation(value = "根据ID信息查找一个数据库中的实体信息")
    @GetMapping(value = "/findById/{id}", produces = "application/json")
    @ResponseBody
    public Object findById(@PathVariable I id) {
        return transform(this.service.findById(id));
    }

    /**
     * @param pageNumber number order of current page
     * @param pageSize size of current page
     * @return pageable entity list
     */
    @ApiOperation(value = "对数据库数据进行分页，高级别筛选查询")
    @ApiImplicitParams({
      @ApiImplicitParam(
        name = "pageNumber",
        value = "分页操作的请求页码，从1开始",
        dataType = "String",
        paramType = "path",
        required = true),
      @ApiImplicitParam(
        name = "pageSize",
        value = "分页操作的请求一页数据的数量",
        dataType = "String",
        paramType = "path",
        required = true),
      @ApiImplicitParam(
        name = "requestBodyStr",
        value = "用该参数是为了高级查询；"
          + "该参数是前端发送的request body数据，然后具体的方法处理这些数据（json格式）达到高级查询过滤的作用；"
          + "body数据为空时（'{}'），则表示不使用过滤操作，只是简单的分页查询操作。",
        paramType = "body",
        dataType = "String",
        required = false,
        defaultValue = "{}")
    })
    @PostMapping(value = "/getList/{pageNumber}/{pageSize}", produces = "application/json")
    @ResponseBody
    public Object getList(@PathVariable String pageNumber,
      @PathVariable String pageSize,
      @RequestBody String requestBodyStr) {
        int page = 0;
        if (StringUtils.isNotBlank(pageNumber)) {
            page = Integer.parseInt(pageNumber) - 1;
        }
        int size = 20;
        if (StringUtils.isNotBlank(pageSize)) {
            size = Integer.parseInt(pageSize);
        }

        Page<T> resultPage;
        // 构建分页
        Pageable pageable = createPageable(page, size);
        // 构建高级过滤
        log.info("requestBodyStr: {}", requestBodyStr);
        if (StringUtils.isNotEmpty(requestBodyStr)) {
            Specification<T> specification = createSpecification(requestBodyStr);
            log.info("specification: {}", specification);
            // 如果前端传入参数，但是后端没有对该参数做处理，则仍然不使用
            resultPage = specification != null ?
              this.service.findAll(specification, pageable) : this.service.findAll(pageable);
        } else {
            resultPage = this.service.findAll(pageable);
        }
        // 如果需要则对查询出来的结果做转换操作，默认transform方法不做任何处理直接返回
        Object result = transform(resultPage);
        log.info("page:{}, size: {}, resultPage: {}", page, size, result);
        return result;
    }

    /**
     * @param id entity code to update
     * @param model entity information to update
     * @param request http请求，用户可以通过该方法接受格外的自定义参数
     * @return updated entity
     */
    @ApiOperation(value = "根据ID对数据库实体数据进行更新操作")
    @PutMapping(value = "/update/{id}", produces = "application/json", consumes = "application/json")
    @ResponseBody
    public T update(@PathVariable I id, @RequestBody T model, HttpServletRequest request) {
        model = updateModelCheck(id, model, request);
        if (model == null) {return null;}
        model = setCommonAttr(model, false);
        model = this.service.save(model);
        return model;
    }

    /**
     * @param model entity model
     * @param request http请求，用户可以通过该方法接受格外的自定义参数
     * @return new created entity
     */
    @ApiOperation(value = "用来添加一个数据实体到数据库")
    @PostMapping(value = "/add", produces = "application/json", consumes = "application/json")
    @ResponseBody
    public T add(@RequestBody T model, HttpServletRequest request) {
        model = addModelCheck(model, request);
        if (model == null) {return null;}
        model = setCommonAttr(model, true);
        model = this.service.save(model);
        return model;
    }
}
